/**
 * 记录最大的层级数
 */
export let zIndexMax = 999;

type ElementStyleTyle = {
    left?: number,
    top?: number,
    zIndex?: number,
    width?: number,
    height?: number
}

export class useElementDragable {
    /**
     * 触发事件的元素
     */
    triggerEvents: HTMLElement | null;
    /**
     * 需要发生改变的元素
     */
    undergoneChanges: HTMLElement | null;
    /**
     * 拉伸元素注册
     */
    stretchingEvents: HTMLElement | null;
    /**
     * 是否暂时性的取消拖拽效果
     */
    DragVisabled: boolean = true;
    /**
     * 是否允许拖动
     */
    isMove: boolean = false;
    /**
     * 是否是拉伸事件
     */
    isStretching: boolean = false;
    /**
     * 鼠标初次按下时x位置，
     * 如果是拖拽事件，该变量是相对于外层元素的offsetX
     * 如果是拉伸事件，则该变量是本地点击的x位置
     */
    baseX: number = 0;
    /**
     * 鼠标初次按下时y位置
     * 如果是拖拽事件，该变量是相对于外层元素的offsetY
     * 如果是拉伸事件，则该变量是本地点击的y位置
     */
    baseY: number = 0;
    /**
     * 原始宽
     */
    BaseWidth: number = 0;
    /**
     * 原始高
     */
    BaseHeight: number = 0;
    /**
     * 拉伸的横向最小值
     */
    StretchingCriticalX: number = 80;
    /**
     * 拉伸的纵向最小值
     */
    StretchingCriticalY: number = 50
    /**
     * 拖拽横向的最小偏移量
     */
    DRAGOFFSETY: number = 20;
    /**
     * 添加拖拽事件
     * @param triggerEvents 触发事件的元素
     * @param undergoneChanges 需要发生改变的元素
     * @param stretchingEvents 拉伸元素注册
     */
    constructor(triggerEvents?: HTMLElement, undergoneChanges?: HTMLElement, stretchingEvents?: HTMLElement) {
        this.triggerEvents = triggerEvents ? triggerEvents : null;
        this.undergoneChanges = undergoneChanges ? undergoneChanges : null;
        this.stretchingEvents = stretchingEvents ? stretchingEvents : null;
        if (this.triggerEvents && this.undergoneChanges) {
            this.addEventDrag();
        }
        return this;
    }
    /**
     * 添加拖拽事件
     */
    addEventDrag() {
        this.triggerEvents?.addEventListener("mousedown", this.ElementMouseDown.bind(this));
        this.stretchingEvents?.addEventListener("mousedown", this.ElementStretchingDown.bind(this));

        window.addEventListener("mousemove", this.ElementMouseMove.bind(this));
        window.addEventListener("mouseup", this.ElementMouseUp.bind(this));

        this.zIndexInc();
        this.updateElementStyle({ zIndex: zIndexMax })
    }
    /**
     * 鼠标点下时触发的时间
     * @param e 
     */
    ElementMouseDown(e: any) {
        e.preventDefault();
        this.DragVisabled && (this.isMove = true);
        this.baseX = e.offsetX;
        this.baseY = e.offsetY;
        this.zIndexInc();
        this.updateElementStyle({ zIndex: zIndexMax })
    };
    /**
     * 鼠标点下时触发  
     * 拉伸元素
     */
    ElementStretchingDown(e: any) {
        e.preventDefault();
        this.DragVisabled && (this.isStretching = true);
        let element = this.undergoneChanges;
        if (!element) return false;
        let { width, height } = element.getBoundingClientRect();

        // 记录基本的宽高
        this.BaseWidth = width;
        this.BaseHeight = height;

        // 记录最开始的位置
        this.baseX = e.pageX;
        this.baseY = e.pageY;

    }
    /**
     * 鼠标移动时触发的时间
     * @param e 
     */
    ElementMouseMove(e: any) {
        if (!this.undergoneChanges || (this.isStretching && this.isMove)) return false;

        e.preventDefault();

        let element = this.undergoneChanges;
        let { width, height } = element.getBoundingClientRect();

        let { pageX, pageY } = e;

        // 移动事件
        if (this.isMove) {
            let _left = pageX - this.baseX;

            let _top = pageY - this.baseY;

            // 先取最大值，再取最小值，防止被拖拽的元素移除屏幕
            let left = Math.max(_left, 0);
            let top = Math.max(_top, 0);

            left = Math.min(left, (window.innerWidth - width - this.DRAGOFFSETY))
            top = Math.min(top, (window.innerHeight - height))

            this.updateElementStyle({
                top,
                left
            })

        }
        // 拉伸事件
        if (this.isStretching) {

            let _width = this.BaseWidth + (pageX - this.baseX);
            let _height = this.BaseHeight + (pageY - this.baseY);

            let width = Math.max(_width, this.StretchingCriticalX)
            let height = Math.max(_height, this.StretchingCriticalY)

            this.updateElementStyle({
                width,
                height
            })
        }
    }
    // 修改元素样式
    updateElementStyle(params: ElementStyleTyle) {
        let { left, top, zIndex, width, height } = params;
        let element = this.undergoneChanges;

        if (!element) return false;

        left && (element.style.left = left + "px");
        top && (element.style.top = top + "px");
        zIndex && (element.style.zIndex = zIndex.toString());
        width && (element.style.width = width + "px");
        height && (element.style.height = height + "px");
    }
    /**
     * 鼠标松开时触发的时间
     * @param e 
     */
    ElementMouseUp(e: any) {
        this.isMove = false;
        this.isStretching = false;
    };
    /**
     * 增加元素层级
     * @param num 
     */
    zIndexInc(num?: number) {
        num ? zIndexMax += num : zIndexMax++;
    }
    /**
     * 减少元素层级
     * @param num 
     */
    zIndexDec(num?: number) {
        num ? zIndexMax -= num : zIndexMax--;
    }
    /**
     * 关闭或添加拖拽事件
     * @param visable true :开启 false :关闭
     */
    setDragHandle(visable: boolean) {
        this.DragVisabled = visable;
    }
    /**
     * 销毁拖拽事件
     */
    destroyHandle() {
        let self = this;
        self.triggerEvents?.removeEventListener("mousedown", self.ElementMouseDown);
        self.stretchingEvents?.removeEventListener("mousedown", self.ElementStretchingDown);
        window.removeEventListener("mousemove", self.ElementMouseMove);
        window.removeEventListener("mouseup", self.ElementMouseUp);
    }
    /**
     * 销毁类方法
     */
    destroy() {
        let self = this;
        self.destroyHandle();
        self.triggerEvents = null;
        self.undergoneChanges = null;
    }

}